/*
 * DriverBanco.java
 * Autor: Jennifer Pamela Valdez Cabrera
 * Carne: 10189
 * Fecha de entrega: 7 de septiembre de 2011
 * Descripcion: Es la simulación de un banco de cuatro ventanillas de atención en donde se muestra
 *      a que tiempo entra cada cliente y cuanto tardará su transacción; y al momento de salir se 
 *      muestra a que hora sale y cuanto tiempo esperó en el banco en total.
*/

import java.util.InputMismatchException;
import java.util.LinkedList;
import java.util.Scanner;


public class DriverBanco {
    
    public static void main(String[] args) {
        //variables
        LinkedList<Cliente> listaEventos = new LinkedList<Cliente>();
        int[] tiemposEspera = new int[4];
        int[] tamColas = new int[4];
        Cliente cliente;
        int  num;
        int  index;
        int  tiempoProm=0;
        int  contClientes=0;
        int  timeAnterior=0;
        boolean  error; 
        LinkedList<Cliente> cola1 = new LinkedList<Cliente>();
        LinkedList<Cliente> cola2 = new LinkedList<Cliente>();
        LinkedList<Cliente> cola3 = new LinkedList<Cliente>();
        LinkedList<Cliente> cola4 = new LinkedList<Cliente>();
        
        instrucciones();
        
        //+-- se piden las horas de entrada de los clientes 
        do{
            error = false;
            num = pedirNumero("Ingrese el tiempo de entrada del cliente: ");
            if (num>0 && num<481){
                if (num<timeAnterior)
                    System.out.println("--> Ese tiempo ya paso!");
                else{
                    timeAnterior = num;
                    cliente = new Cliente(num, num, 0, 0);
                    listaEventos.addLast(cliente);
                }
            }
            else{
                error = true;
                if (num>480)
                    System.out.println("--> El Banco ya cerro!");
            }
        }while (!error);
       
       //+-- inicializar vectores --+
        for (int i=0; i<4;i++){
            tiemposEspera[i] = 0;
            tamColas[i] = 0;
        }  
        
        while (!listaEventos.isEmpty()){
            cliente = listaEventos.removeFirst();
            int temp;
            if (cliente.getEvento() == 0){  //ingresarlo a una cola
                index = min(tamColas);
                switch(index){
                    case 0:  // entro a la primera ventana
                        cola1.add(cliente);
                        tamColas[0] = cola1.size();
                        cliente.setVentanilla(1);
                        desplegarDatos(cliente);  //muestra que entro cliente
                        tiemposEspera[0] += cliente.getTimeAction();
                        if (tamColas[0] == 1)
                            temp = cola1.peek().getHora()+tiemposEspera[0];
                        else
                            temp = cola1.peek().getHora()+tiemposEspera[0]-cola1.peek().getTimeAction();
                        cliente.setHora(temp);
                        cliente.setEvento(1);
                        index = getIndice(cliente.getHora(), listaEventos);
                        listaEventos.add(index, cliente); // agrega cuando sale a la lista
                        contClientes++;
                        break;
                    case 1:  // entro a la ventana 2
                        cola2.add(cliente);
                        tamColas[1] = cola2.size();
                        cliente.setVentanilla(2);
                        desplegarDatos(cliente);  // muestra que entro el cliente
                        tiemposEspera[1] += cliente.getTimeAction();
                        if (tamColas[1] == 1)
                            temp = cola2.peek().getHora()+tiemposEspera[1];
                        else
                            temp = cola2.peek().getHora()+tiemposEspera[1]-cola2.peek().getTimeAction();
                        cliente.setHora(temp);
                        cliente.setEvento(1);
                        index = getIndice(cliente.getHora(), listaEventos);
                        listaEventos.add(index, cliente);  // agrega cuando sale a la lista
                        contClientes++;
                        break;
                    case 2: // entro a la ventana 3
                        cola3.add(cliente);
                        tamColas[2] = cola3.size();
                        cliente.setVentanilla(3);
                        desplegarDatos(cliente); // muestra que entro el cliente
                        tiemposEspera[2] += cliente.getTimeAction();
                        if (tamColas[2] == 1)
                            temp = cola3.peek().getHora()+tiemposEspera[2];
                        else
                            temp = cola3.peek().getHora()+tiemposEspera[2]-cola3.peek().getTimeAction();
                        cliente.setHora(temp);
                        cliente.setEvento(1);
                        index = getIndice(cliente.getHora(), listaEventos);
                        listaEventos.add(index, cliente); // agrega cuando sale a la lista
                        contClientes++;
                        break;
                    case 3:  // entro a la ventana 4
                        cola4.add(cliente);
                        tamColas[3] = cola4.size();
                        cliente.setVentanilla(4);
                        desplegarDatos(cliente);  // muestra que entro el cliente
                        tiemposEspera[3] += cliente.getTimeAction();
                        if (tamColas[3] == 1)
                            temp = cola4.peek().getHora()+tiemposEspera[3];
                        else
                            temp = cola4.peek().getHora()+tiemposEspera[3]-cola4.peek().getTimeAction();
                        cliente.setHora(temp);
                        cliente.setEvento(1);
                        index = getIndice(cliente.getHora(), listaEventos);
                        listaEventos.add(index, cliente);  // agrega cuando sale a la lista
                        contClientes++;
                        break;
                    case 4:  // todas estan llenas se va el cliente
                            System.out.println("Las colas estan llenas, el cliente debe irse");
                        break;
                }
            }
        }
        
        System.out.println("\nTotal clientes: " + contClientes);
        if (contClientes == 0)
            System.out.println("Tiempo de espera promedio: 0 minutos");
        else
            System.out.println("Tiempo de espera promedio: "+ tiempoProm/contClientes+" minutos.");
        
    }
    
    //min: devuelve el indice en donde se encuentra el menor
    public static int min(int[] vector){
        int minValue = vector[0];
        int indice = 0;
        
        for (int i=1; i<4; i++){
            if (vector[i]<minValue){
                minValue = vector[i];
                indice = i;
            }
        }
        
        if (minValue == 10)  // si todas estan llenas
            indice = 4;
        
        return indice;
    }
    
    //desplegarDatos: despliega el conjunto de numeros
    public static int getIndice(int numero, LinkedList<Cliente> lista){
       int indice = 0;
       int tamanio = lista.size();
       boolean find = false;
       for (int i=0; i<tamanio && !find; i++){
           if (numero <= lista.get(i).getHora()){
               indice = i;
               find = true;
           }
       }
       if (!find)
           indice = tamanio;
       return indice;
    }
    
    //desplegarDatos: despliega el conjunto de numeros
    public static void desplegarDatos(Cliente client){
        if (client.getEvento() == 0)
            System.out.println("Ha entrado un cliente al tiempo "+client.getHora()+" a la ventanilla "+client.getVentanilla()+" y su transaccion tardara "+ client.getTimeAction()+" minutos");
        else
            System.out.println("Ha salido un cliente al tiempo "+client.getHora()+" de la ventanilla "+client.getVentanilla()+" y estuvo "+ (client.getHora()-client.getTimeIn()) + " minutos en el banco.");
    }
    
    //pedirNumero: pide el numero de la opcion ya validado
    //parametro tipo String que es la pregunta previa a que el usuario introduzca el numero
    //devuelve el entero con el valor
    public static int pedirNumero(String texto){
        Scanner readln = new Scanner(System.in);
        boolean pedir;
        int numero = 0;
        do{
            numero = 0;
            pedir = false;
            try{
                    System.out.println(texto);
                    numero = readln.nextInt();
                    pedir = false;
            }
            catch(InputMismatchException exception){
                    pedir = true;
                    System.out.println("\n ERROR --> NUMERO NO VALIDO \n");
            }
        readln.nextLine();
        }while (pedir);
        return numero;
    }
    
    //instrucciones: muestra las instrucciones
    public static void instrucciones(){
        System.out.println("\n+--  INSTRUCCIONES   -------------------------------+");
        System.out.println("| Debe ingresar los tiempos a los que los clientes  |");
        System.out.println("| ingresan al banco, puede ser desde el tiempo 1    |");
        System.out.println("| hasta el tiempo 480; para terminar de ingresar a  |");
        System.out.println("| los clientes ingrese un numero negativo.          |");
        System.out.println("+---------------------------------------------------+\n");
    }
}

